package components;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.text.AttributedString;

import javax.swing.SwingUtilities;
import javax.swing.Timer;

import client.TableFrame;

/**
 * 
 * timer countdown
 *
 */
public class Countdown extends RPSPanel implements ActionListener {

	private static final long serialVersionUID = 2342;
	
	private static final int SECOND = 1080;
	private static final int ANGLES_IN_CIRCLE = 360;
	
	
	private static final String ACTION_COMMAND_SECONDS = "seconds";
	private static final String ACTION_COMMAND_ARC     = "arc";
	
	private static final int    ARC_ALPHA = (int)(255 * 0.75);
	private static final int    ARC_START_ANGLE = 90;
	
	private static final int CIRCLE_STROKE_WIDTH = 8;
	private static final Color CIRCLE_STROKE_COLOR = Color.BLACK;
	private static final int CIRCLE_RADIUS = 90;
	private static final int CIRCLE_DIAMETER = 2 * CIRCLE_RADIUS;
	private static final int SPACE_FROM_EACH_SIDE = 5;
	public  static final int TOTAL_WIDTH = 2 * (CIRCLE_RADIUS + CIRCLE_STROKE_WIDTH/2 + SPACE_FROM_EACH_SIDE);
	public  static final int TOTAL_HEIGHT = TOTAL_WIDTH;
	private static final int GRADIENT_POINT1_OFFSET = -15;
	private static final int GRADIENT_POINT2_OFFSET = 5;
	private static final int PADDING_FOR_GRAPHICS_INACCURACY = 1;
	
	private static final String FONT_NAME = "SansSerif";
	private static final int    FONT_STYLE = Font.BOLD;
	private static final int    FONT_SIZE = 48;
	private static final Color  FONT_COLOR = Color.BLACK;
	
	private Timer timer;
	private Timer arcTimer;
	private Color arcColor;
	private int arcAngle = 0;
	private int timeSet;
    private int timeLeft;

    private TableFrame tableFrame = null;

    private int posX;
    private int posY;
    private Ellipse2D ellipse = null;
    private GradientPaint gp = null;
    private int arcX1;
    private int arcY1;
    private int arcX2;
    private int arcY2;
	private Font font = null;
	private FontRenderContext frc = null;

    
	public Countdown(int time, TableFrame tableFrame) {
		super();
		
		this.tableFrame = tableFrame;
		
		setSize(TOTAL_WIDTH, TOTAL_WIDTH);
		
		setDrawingVariables();

		setTimer(time, Color.RED);
	}
	
	
	/**
	 * Settings some values for drawing the different parts of the CountDown, so they wouldn't have to be calculated
	 * in every timer tick
	 */
	private void setDrawingVariables()
	{
		// Set all-around constants
		posX = getWidth()/2;
	    posY = getHeight()/2;
	    
	    // Set circle drawing constants
	    ellipse = new Ellipse2D.Double(posX - CIRCLE_RADIUS, posY - CIRCLE_RADIUS , CIRCLE_DIAMETER, CIRCLE_DIAMETER);
	    gp = new GradientPaint(CIRCLE_RADIUS + GRADIENT_POINT1_OFFSET, CIRCLE_RADIUS + GRADIENT_POINT1_OFFSET, Color.white,
				 			   CIRCLE_RADIUS + GRADIENT_POINT2_OFFSET, CIRCLE_RADIUS + GRADIENT_POINT2_OFFSET, Color.gray, true);
	    
	    
	    // Set arc drawing constants
		arcX1 = posX - CIRCLE_RADIUS + CIRCLE_STROKE_WIDTH/2 - PADDING_FOR_GRAPHICS_INACCURACY;
		arcY1 = posY - CIRCLE_RADIUS + CIRCLE_STROKE_WIDTH/2 - PADDING_FOR_GRAPHICS_INACCURACY;
		arcX2 = CIRCLE_DIAMETER - CIRCLE_STROKE_WIDTH + 2*PADDING_FOR_GRAPHICS_INACCURACY;
		arcY2 = CIRCLE_DIAMETER - CIRCLE_STROKE_WIDTH + 2*PADDING_FOR_GRAPHICS_INACCURACY;
		
	    // Set number drawing constants
		font = new Font(FONT_NAME, FONT_STYLE, FONT_SIZE);
		frc = new FontRenderContext(new AffineTransform(),true, false);
	}

	public void paintComponent (Graphics g) {
		super.paintComponent(g);
		
		drawCircle(g);
		drawArc(g);
		drawStroke(g);
		drawNum(g);
	}
	
	private void drawCircle(Graphics g) {
	    Graphics2D g2 = (Graphics2D)g;

	    // Fill with a gradient.
	    g2.setPaint(gp);
	    g2.fill(ellipse);
	}

	private void drawArc(Graphics g) {
		Color transparentArcColor = new Color(arcColor.getRed(), arcColor.getGreen(), arcColor.getBlue(), ARC_ALPHA);
		
		g.setColor(transparentArcColor);

		g.fillArc(arcX1, arcY1, arcX2, arcY2, ARC_START_ANGLE, arcAngle);
	}

	private void drawStroke(Graphics g)
	{
	    Graphics2D g2 = (Graphics2D)g;
	    
	    g2.setPaint(CIRCLE_STROKE_COLOR);
	    g2.setStroke(new BasicStroke(CIRCLE_STROKE_WIDTH));
	    g2.draw(ellipse);
	}
	
	private void drawNum(Graphics g) {
		String strTimeLeft = String.valueOf(timeLeft);

		Rectangle2D titleBounds = font.getStringBounds(strTimeLeft, frc);
		double sWidth = titleBounds.getWidth();
		double sHeight = titleBounds.getHeight() - 25 ;
		AttributedString atr = new AttributedString(String.valueOf(strTimeLeft));
		atr.addAttribute(TextAttribute.FONT, font);

		g.setColor(FONT_COLOR);
		
		g.drawString(atr.getIterator(), (int) (posX - sWidth/2), (int)(posY + sHeight/2));
	}

	@Override
	public void actionPerformed(final ActionEvent event) {
		Runnable doWorkRunnable = new Runnable() {
		    public void run() { 

		    	repaint();
		    	
				if (event.getActionCommand().equals(ACTION_COMMAND_SECONDS)) {
			    	--timeLeft;
			    	
			    	if (timeLeft == 0) {
			    		freeze();
			    		tableFrame.countdownFinished();
			    	}
				}
				else if (event.getActionCommand().equals(ACTION_COMMAND_ARC)) {
					--arcAngle;
					
					if (arcAngle == -360) {
						arcAngle = 0;
					}
				}
		    }
		};
		SwingUtilities.invokeLater(doWorkRunnable);
	}

	
	public void startTimer () {
		timer.start();
		arcTimer.start();
		setVisible(true);
	}

	public void restart() {
		timeLeft = timeSet;
		timer.restart();
		arcTimer.restart();
		arcAngle = 0;
		

		if (arcColor.equals(Color.RED))
		{
			arcColor = Color.BLUE;
		}
		else
		{
			arcColor = Color.RED;
		}
		
		repaint();
		
	}
	
	public void freeze() {
		timer.stop();
		arcTimer.stop();
		repaint();
	}
	
	public void setTimer(int time, Color color)
	{
		timer = new Timer(SECOND, this);
		timer.setActionCommand(ACTION_COMMAND_SECONDS);
		timer.setInitialDelay(SECOND);
		timeLeft = time; 
		arcTimer = new Timer(SECOND / ANGLES_IN_CIRCLE, this);		
		arcTimer.setActionCommand(ACTION_COMMAND_ARC);
		arcTimer.setInitialDelay(0);
		arcAngle = 0;
		arcColor = color;
		timeSet = time;
	}
}
